package com.cmbc.connect;

import java.util.HashMap;
import java.util.Map;

import org.budo.support.fastjson.Fastjson;
import org.budo.support.lang.util.StringUtil;
import org.springframework.util.Assert;

import com.alibaba.fastjson.JSONObject;

import cfca.httpclient.CmbcHttpClient;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 */
@Getter
@Setter
@Slf4j
public class DBankHttpsMessageSender extends AbstractMessageSender {
    private String clientJksPath;

    private String trustJksPath;

    private String clientJksPwd;

    private String trustJksPwd;

    /**
     * @param merchantPrivateKeyPath : 商户私钥
     * @param merchantPemPfxPin      : 秘钥pin
     * @param bankCertPath           : 银行公钥
     * @param url                    : 请求URL
     * @param merchantNo             : 商户号
     */
    public DBankHttpsMessageSender(String privateKeyPath, String pemPfxPin, String publicKeyPath, String url, String merchantNo, String clientJksPath, String trustJksPath, String clientJksPwd, String trustJksPwd) {
        Assert.hasText(privateKeyPath, "#43 privateKeyPath");
        Assert.hasText(pemPfxPin, "#44 pemPfxPin");
        Assert.hasText(publicKeyPath, "#45 publicKeyPath");
        Assert.hasText(url, "#46 url");
        Assert.hasText(merchantNo, "#47 merchantNo");

        Assert.hasText(clientJksPath, "#49 clientJksPath");
        Assert.hasText(trustJksPath, "#50 trustJksPath");
        Assert.hasText(clientJksPwd, "#51 clientJksPwd");
        Assert.hasText(trustJksPwd, "#52 trustJksPwd");

        this.setEncrypter(new SM2Encrypter(publicKeyPath, privateKeyPath, pemPfxPin));
        this.setUrl(url);
        this.setMerchantNo(merchantNo);

        this.clientJksPath = clientJksPath;
        this.trustJksPath = trustJksPath;
        this.clientJksPwd = clientJksPwd;
        this.trustJksPwd = trustJksPwd;
    }

    public String sendMessage(String sendTransCode, Map<String, Object> message, String channelJnlNo) {
        Assert.hasText(sendTransCode, "#65 sendTransCode");
        Assert.hasText(channelJnlNo, "#66 channelJnlNo");

        if (message == null) {
            message = new HashMap<String, Object>();
        }

        // 添加头信息
        this.addHeader(message, channelJnlNo);

        // 添加交易码
        this.addSendTransCode(sendTransCode, message);

        // 加密
        String requestData = new JSONObject(message).toString();
        String requestDataEncrypt = null;
        try {
            requestDataEncrypt = this.getEncrypter().encryptAndSignMessage(requestData);
        } catch (Throwable e) {
            log.error("#67 e=" + e + ", 原始报文信息=" + message, e);
            throw new ConnectException("报文加密失败", e);
        }

        // 组装加密后准备发送给服务端的报文
        JSONObject jsonContent = new JSONObject();
        jsonContent.put(Constant.RequestData, requestDataEncrypt);
        jsonContent.put(Constant.MerchantNo, this.getMerchantNo());
        jsonContent.put(Constant.SignFlag, "1");

        if (log.isDebugEnabled()) {
            log.debug("#92 sendMessage, sendTransCode=" + sendTransCode + ", jsonContent=" + jsonContent);
        }

        // 发送
        String responseBody = null;
        try {
            CmbcHttpClient httpConnector = new CmbcHttpClient();
            httpConnector.init(this.getClientJksPath(), this.getTrustJksPath(), this.getClientJksPwd(), this.getTrustJksPwd());
            responseBody = httpConnector.post(this.getUrl(), jsonContent.toString());
        } catch (Throwable e) {
            log.error("#103 httpConnector.post error, e=" + e, e);
            throw new ConnectException("#104 httpConnector.post error, url=" + this.getUrl(), e);
        }

        // 解密报文
        String responseDecrypt = null;
        try {
            JSONObject parseObject = JSONObject.parseObject(responseBody);
            String responseContent = parseObject.getString(Constant.Content);
            responseDecrypt = this.getEncrypter().decryptAndVerifyMessage(responseContent);
        } catch (Throwable e) {
            log.error("#99 e=" + e + ", 原始报文信息=" + responseBody, e);
            throw new ConnectException("#110 报文解密失败, responseBody=" + responseBody, e);
        }

        String requestLog = Fastjson.summary(requestData);
        log.info("#115 requestData=" + requestLog + ", responseDecrypt=" + StringUtil.cutLeft(responseDecrypt, 1024));
        return responseDecrypt;
    }
}